package com.starbaba.core.utils;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.xml.ResourceEntityResolver;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;


public class SpringContextManager implements ApplicationContextAware, DisposableBean{
	
	private static ApplicationContext applicationContext = null;

	private static Logger logger = LoggerFactory.getLogger(SpringContextManager.class);


	/**
	 * 实现ApplicationContextAware接口, 注入Context到静态变量中.
	 */
	@Override
	public void setApplicationContext(ApplicationContext applicationContext) {
		logger.debug("注入ApplicationContext到SpringContextHolder:" + applicationContext);

		if (SpringContextManager.applicationContext != null) {
			logger.warn("SpringContextManager中的ApplicationContext被覆盖, 原有ApplicationContext为:"
					+ SpringContextManager.applicationContext);
		}

		SpringContextManager.applicationContext = applicationContext; //NOSONAR
	}

	/**
	 * 实现DisposableBean接口,在Context关闭时清理静态变量.
	 */
	@Override
	public void destroy() throws Exception {
		SpringContextManager.clear();
	}

	/**
	 * 取得存储在静态变量中的ApplicationContext.
	 */
	public static ApplicationContext getApplicationContext() {
		assertContextInjected();
		return applicationContext;
	}

	/**
	 * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
	 */
	@SuppressWarnings("unchecked")
	public static <T> T getBean(String name) {
		assertContextInjected();
		return (T) applicationContext.getBean(name);
	}

	/**
	 * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
	 */
	public static <T> T getBean(Class<T> requiredType) {
		assertContextInjected();
		return applicationContext.getBean(requiredType);
	}

	/**
	 * 清除SpringContextHolder中的ApplicationContext为Null.
	 */
	public static void clear() {
		logger.debug("清除SpringContextManager中的ApplicationContext:" + applicationContext);
		applicationContext = null;
	}

	/**
	 * 检查ApplicationContext不为空.
	 */
	private static void assertContextInjected() {
		if (applicationContext == null) {
			throw new IllegalStateException("applicaitonContext未注入,请在applicationContext.xml中定义SpringContextManager");
		}
	}
	
	/**
	 * 向spring的beanFactory动态地装载bean
	 * 
	 * @param configLocationString  要装载的bean所在的xml配置文件位置。 
	 * 			spring配置中的contextConfigLocation，同样支持诸如 "classpath*:/WEB-INF/ApplicationContext-*.xml"的写法。
	 * 			多个路径使用“,”分隔，如：“classpath*:/WEB-INF/ApplicationContext-First.xml,classpath*:/WEB-INF/ApplicationContext-Second.xml”。
	 */
	public static void loadBean(String configLocationString) {
		if(org.apache.commons.lang.StringUtils.isBlank(configLocationString)) {
			logger.warn("param 'configLocationString' could not been null!");
		}
		
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(
				(BeanDefinitionRegistry) ((ConfigurableApplicationContext)getApplicationContext()).getBeanFactory());
		beanDefinitionReader.setResourceLoader(getApplicationContext());
		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(getApplicationContext()));
		try {
			
//			String[] configLocations = new String[]{configLocationString};
			String[] configLocations = StringUtils.split(configLocationString, ",");
			if(logger.isInfoEnabled()) {
				logger.info("Load Configurations: " +configLocations);
			}
			if(ArrayUtils.isNotEmpty(configLocations)) {
				beanDefinitionReader.loadBeanDefinitions(configLocations);
				
				/*for(String s: configLocations) {
					beanDefinitionReader.loadBeanDefinitions(getApplicationContext().getResources(s));
				}*/
			}
			
		} catch (BeansException e) {
			logger.error(e.getMessage(), e);
		}
	}

}
